﻿//=============================================================================
// System  : JavaScript Compressor
// File    : JSCompressor.cs
// Author  : Eric Woodruff  (Eric@EWoodruff.us)
// Updated : 06/26/2006
// Note    : Copyright 2003-2006, Eric Woodruff, All rights reserved
// Compiler: Visual C#
//
// This class is used to compress JavaScript code by removing all comments,
// extraneous whitespace, and line feeds where possible (optional).
//
// This code may be used in compiled form in any way you desire.  This
// file may be redistributed unmodified by any means PROVIDING it is not
// sold for profit without the author's written consent, and providing
// that this notice and the author's name and all copyright notices
// remain intact.
//
// This code is provided "as is" with no warranty either express or
// implied.  The author accepts no liability for any damage or loss of
// business that this product may cause.
//
// Version     Date     Who  Comments
// ============================================================================
// 1.0.0.0  07/21/2002  EFW  Created the code
// 2.0.0.0  03/04/2006  EFW  Rebuilt and tested with VS 2005 and .NET 2.0 and
//                           added support for compressing variable names.
// 2.0.0.1  06/26/2006  EFW  Modified to support conditional compilation blocks
//=============================================================================

using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Text;

namespace blackhouse.Web.FasterFiles
{
    /// <summary>
    /// This class is used to compress JavaScript code.
    /// </summary>
    /// <remarks>Compression in this case consists of removing comments
    /// and unnecessary whitespace.  It can also remove almost all line
    /// feed characters between lines provided that semi-colons have been
    /// used to indicate all statement endpoints.</remarks>
    public class JSCompressor : ICompressOutput
    {

        #region ICompressOutput Members

        public string CompressOutput(string content)
        {
            string[] lines = content.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            StringBuilder emptyLines = new StringBuilder();
            foreach (string line in lines)
            {
                string s = line.Trim();
                if (s.Length > 0 && !s.StartsWith("//"))
                    emptyLines.AppendLine(s.Trim());
            }
            content = emptyLines.ToString();
            // remove C styles comments
            content = Regex.Replace(content, "/\\*.*?\\*/", String.Empty, RegexOptions.Compiled | RegexOptions.Singleline);
            //// trim left
            content = Regex.Replace(content, "^\\s*", String.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
            //// trim right
            content = Regex.Replace(content, "\\s*[\\r\\n]", "\r\n", RegexOptions.Compiled | RegexOptions.ECMAScript);
            // remove whitespace beside of left curly braced
            content = Regex.Replace(content, "\\s*{\\s*", "{", RegexOptions.Compiled | RegexOptions.ECMAScript);
            // remove whitespace beside of coma
            content = Regex.Replace(content, "\\s*,\\s*", ",", RegexOptions.Compiled | RegexOptions.ECMAScript);
            // remove whitespace beside of semicolon
            content = Regex.Replace(content, "\\s*;\\s*", ";", RegexOptions.Compiled | RegexOptions.ECMAScript);
            // remove newline after keywords 
            content = Regex.Replace(content, "\\r\\n(?<=\\b(abstract|boolean|break|byte|case|catch|char|class|const|continue|default|delete|do|double|else|extends|false|final|inally|float|for|function|goto|if|implements|import|in|instanceof|int|interface|long|native|new|null|package|private|protected|public|return|short|static|super|switch|synchronized|this|throw|throws|transient|true|try|typeof|var|void|while|with)\\r\\n)", " ", RegexOptions.Compiled | RegexOptions.ECMAScript);
            content = Regex.Replace(content, @"[\n\r]+\s*", string.Empty); // space
            return content;
        }

        #endregion
    }
}
